home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / telecomm / misc / xprzmodem.lha / Source / receive.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-13  |  19.0 KB  |  750 lines

  1. /**********************************************************************
  2.  * Receive.c:  File reception routines for xprzmodem.library;
  3.  * Version 2.10, 12 February 1991, by Rick Huebner.
  4.  * Based closely on Chuck Forsberg's rz.c example ZModem code,
  5.  * but too pervasively modified to even think of detailing the changes.
  6.  * Released to the Public Domain; do as you like with this code.
  7.  *
  8.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  9.  * Version 2.53, 28 June 1993, several additions by Olaf `Olsen' Barthel
  10.  **********************************************************************/
  11.  
  12. /* Find the end of the string. */
  13. STATIC STRPTR __regargs find_end(register STRPTR buf)
  14. {
  15.   while (*buf)
  16.     buf++;
  17.  
  18.   return (buf);
  19. }
  20.  
  21. /* Convert octal number to decimal. */
  22. STATIC ULONG __regargs from_octal(STRPTR buf)
  23. {
  24.   register ULONG value = 0;
  25.   register UBYTE c;
  26.  
  27.   while (c = *buf)
  28.   {
  29.     if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  30.       buf++;
  31.     else
  32.       break;
  33.   }
  34.  
  35.   while (c = *buf++)
  36.   {
  37.     if (c >= '0' && c <= '7')
  38.       value = (value << 3) + (c - '0');
  39.     else
  40.       break;
  41.   }
  42.  
  43.   return (value);
  44. }
  45.  
  46. /* Skip all blanks. */
  47. STATIC STRPTR __regargs skip_chars(register STRPTR buf)
  48. {
  49.   register UBYTE c;
  50.  
  51.   while (c = *buf)
  52.   {
  53.     if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  54.     {
  55.       buf++;
  56.  
  57.       while (c = *buf)
  58.       {
  59.     if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  60.       buf++;
  61.     else
  62.       return (buf);
  63.       }
  64.  
  65.       return (buf);
  66.     }
  67.     else
  68.       buf++;
  69.   }
  70.  
  71.   return (buf);
  72. }
  73.  
  74. /**********************************************************
  75.  *      long XProtocolReceive(struct XPR_IO *xio)
  76.  *
  77.  * Main file reception routine; called by comm program
  78.  **********************************************************/
  79. long __saveds __asm XProtocolReceive(register __a0 struct XPR_IO *xio)
  80. {
  81.   struct SetupVars *sv;
  82.   struct Vars *v;
  83.   UBYTE err = FALSE;
  84.  
  85.   /* Perform common setup and initializations */
  86.   if (!(v = setup(xio)))
  87.     return XPRS_FAILURE;
  88.  
  89.   /* Remember data direction for cps rate calculation. */
  90.   v->Receiving = TRUE;
  91.   v->Tryzhdrtype = ZRINIT;
  92.   v->Rxtimeout = 100;
  93.  
  94.   sv = (void *) v->io.xpr_data;
  95.   if (sv->bufpos)
  96.   {
  97.     v->Modemchar = v->Modembuf;
  98.     if (sv->buflen > sizeof(v->Modembuf))
  99.       sv->buflen = sizeof(v->Modembuf);
  100.     memcpy(v->Modembuf, sv->bufpos, sv->buflen);
  101.     v->Modemcount = sv->buflen;
  102.   }
  103.  
  104.   /* Transfer the files */
  105.   if (rcvbatch(v) == ERROR)
  106.   {
  107.     upderr(v, GetLocaleString(MSG_DOWNLOAD_CANCELLED_OR_TIMED_OUT_TXT));
  108.     err = TRUE;
  109.   }
  110.   else
  111.     updmsg(v, GetLocaleString(MSG_DONE_TXT));
  112.  
  113.   /* Clean up and return */
  114.   if (v->io.xpr_setserial && v->Oldstatus != -1)
  115.     (*v->io.xpr_setserial) (v->Oldstatus);
  116.  
  117.   /* If an error occured, it's quite likely that there is
  118.    * garbage in the receive buffer we don't want the user
  119.    * to see.
  120.    */
  121.   if(xio->xpr_sflush)
  122.     (*xio->xpr_sflush)();
  123.  
  124.   FreeMem(v->Filebuf, v->Filebufmax);
  125.   FreeMem(v, (long) sizeof(struct Vars));
  126.  
  127.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  128. }                /* End of long XProtocolReceive() */
  129.  
  130. /**********************************************************
  131.  *      short rcvbatch(struct Vars *v)
  132.  *
  133.  * Start the batch transfer
  134.  **********************************************************/
  135. short rcvbatch(struct Vars *v)
  136. {
  137.   switch (tryz(v))
  138.   {
  139.   case ZCOMPL:
  140.     return OK;
  141.   case ZFILE:
  142.     if (rzfiles(v) == OK)
  143.       return OK;
  144.   }
  145.   canit(v);
  146.   return ERROR;
  147. }                /* End of short rcvbatch() */
  148.  
  149. /**********************************************************
  150.  *      short tryz(struct Vars *v)
  151.  *
  152.  * Negotiate with sender to start a file transfer
  153.  **********************************************************/
  154. short tryz(struct Vars *v)
  155. {
  156.   short n, errors = 0;
  157.  
  158.   for (n = v->ErrorLimit; --n >= 0;)
  159.   {
  160.     /* Set max frame length and capability flags */
  161.     stohdr(v, (long) v->Tframlen);
  162.     v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  163.  
  164.     if (v->Zctlesc)
  165.       v->Txhdr[ZF0] |= TESCCTL;
  166.  
  167.     zshhdr(v, v->Tryzhdrtype);
  168.     sendbuf(v);
  169.  
  170.     if (v->Tryzhdrtype == ZSKIP) /* Don't skip too far. */
  171.       v->Tryzhdrtype = ZRINIT;   /* CAF 8-21-87 */
  172.  
  173.   again:
  174.     /* Check for abort from comm program */
  175.     if (v->io.xpr_chkabort)
  176.     {
  177.       long result = (*v->io.xpr_chkabort) ();
  178.  
  179.       /* Cancel transmission. */
  180.       if (result < 0)
  181.       {
  182.     zshhdr(v, ZABORT);
  183.     sendbuf(v);
  184.     return ERROR;
  185.       }
  186.       else
  187.       {
  188.         /* Skip current file. */
  189.     if (result > 0)
  190.     {
  191.       zshhdr(v, ZSKIP);
  192.       sendbuf(v);
  193.     }
  194.       }
  195.     }
  196.  
  197.     switch (zgethdr(v))
  198.     {
  199.     case ZFILE:        /* File name and info packet */
  200.       v->Zconv = v->Rxhdr[ZF0];        /* Suggested txt mode; ZCNL = text, */
  201.                                         /* ZCBIN = binary, 0 = don't know. */
  202.       v->Zmanag = v->Rxhdr[ZF1];    /* Suggested file management mode. */
  203.       v->Ztrans = v->Rxhdr[ZF2];    /* Suggested file transport mode. */
  204.       v->Tryzhdrtype = ZRINIT;
  205.  
  206.       if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  207.     return ZFILE;
  208.       zshhdr(v, ZNAK);        /* Packet mangled, ask for retry */
  209.       sendbuf(v);
  210.       goto again;
  211.     case ZSINIT:        /* Special attention-grabbing string to use to */
  212.       v->Zctlesc = TESCCTL & v->Rxhdr[ZF0];
  213.       /* interrupt sender */
  214.       if (zrdata(v, v->Attn, ZATTNLEN) == GOTCRCW)
  215.     zshhdr(v, ZACK);
  216.       else
  217.     zshhdr(v, ZNAK);
  218.       sendbuf(v);
  219.       goto again;
  220.     case ZFREECNT:        /* Sender wants to know how much room we've got */
  221.       stohdr(v, getfree(v));
  222.       zshhdr(v, ZACK);
  223.       sendbuf(v);
  224.       goto again;
  225.     case ZCOMMAND:        /* Sender wants us to do remote commands, */
  226.       /* but we don't do requests. */
  227.  
  228.       if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  229.       {
  230.     mysprintf(v->Msgbuf, GetLocaleString(MSG_IGNORING_COMMAND_TXT), v->Pktbuf);
  231.     upderr(v, v->Msgbuf);    /* Ignore and report all uploaded commands */
  232.     stohdr(v, 0L);        /* whilst telling sender they worked; */
  233.     do
  234.     {
  235.       zshhdr(v, ZCOMPL);    /* paranoia can be good for you... */
  236.       sendbuf(v);
  237.     }
  238.     while (++errors < v->ErrorLimit && zgethdr(v) != ZFIN);
  239.     ackbibi(v);
  240.     return ZCOMPL;
  241.       }
  242.       else
  243.     zshhdr(v, ZNAK);
  244.       sendbuf(v);
  245.       goto again;
  246.     case ZCOMPL:
  247.       goto again;
  248.     case ZFIN:            /* Sender has ended batch */
  249.       ackbibi(v);
  250.       return ZCOMPL;
  251.     case ZCAN:
  252.     case RCDO:
  253.       upderr(v, v->Msgbuf);
  254.       return ERROR;
  255.     }
  256.   }
  257.   return ERROR;
  258. }                /* End of short tryz() */
  259.  
  260. /**********************************************************
  261.  *      short rzfiles(struct Vars *v)
  262.  *
  263.  * Receive a batch of files
  264.  **********************************************************/
  265. short rzfiles(struct Vars *v)
  266. {
  267.   struct SetupVars *sv;
  268.   short c;
  269.  
  270.   /* Keep receiving files until end of batch or error */
  271.   while (TRUE)
  272.   {
  273.     switch (c = rzfile(v))
  274.     {
  275.     case ZEOF:
  276.     case ZSKIP:
  277.       switch (tryz(v))
  278.       {
  279.       case ZCOMPL:
  280.     return OK;
  281.       default:
  282.     return ERROR;
  283.       case ZFILE:
  284.     break;
  285.       }
  286.       break;
  287.     default:
  288.       bfclose(v);
  289.       sv = (void *) v->io.xpr_data;
  290.       if (*sv->option_k == 'N' && v->io.xpr_extension >= 2
  291.       && v->io.xpr_unlink)
  292.       {
  293.     updmsg(v, GetLocaleString(MSG_DELETING_PARTIALLY_RECEIVED_FILE_TXT));
  294.     (*v->io.xpr_unlink) (v->Filename);
  295.       }
  296.       else
  297.     updmsg(v, GetLocaleString(MSG_KEEPING_PARTIALLY_RECEIVED_FILE_TXT));
  298.       return c;
  299.     }
  300.   }
  301. }                /* End of short rzfiles() */
  302.  
  303. /**********************************************************
  304.  *      short rzfile(struct Vars *v)
  305.  *
  306.  * Receive one file; file name packet already read into
  307.  * Pktbuf by tryz()
  308.  **********************************************************/
  309. short rzfile(struct Vars *v)
  310. {
  311.   short c, n;
  312.   long result, abort = 0;
  313.  
  314.   /* Process file name packet; either open file and prepare to receive,
  315.    * or tell us to skip this one.
  316.    */
  317.   if (procheader(v) == ERROR)
  318.     return v->Tryzhdrtype = ZSKIP;
  319.  
  320.   n = v->ErrorLimit;
  321.   v->Rxbytes = v->Strtpos;
  322.   v->Eofseen = FALSE;
  323.  
  324.   /* Receive ZDATA frames until finished */
  325.   while (TRUE)
  326.   {
  327.     stohdr(v, v->Rxbytes);    /* Tell sender where to start frame */
  328.     zshhdr(v, ZRPOS);
  329.     sendbuf(v);
  330.   nxthdr:
  331.     /* Check for abort from comm program */
  332.     if (v->io.xpr_chkabort)
  333.     {
  334.       if (abort)
  335.       {
  336.         result = abort;
  337.         abort = 0;
  338.       }
  339.       else
  340.         result = (*v->io.xpr_chkabort) ();
  341.  
  342.       /* Cancel transmission. */
  343.       if (result < 0)
  344.       {
  345.     zshhdr(v, ZABORT);
  346.     sendbuf(v);
  347.       }
  348.       else
  349.       {
  350.         /* Skip current file. */
  351.     if (result > 0)
  352.     {
  353.       zshhdr(v, ZSKIP);
  354.       sendbuf(v);
  355.     }
  356.       }
  357.     }
  358.  
  359.     switch (c = zgethdr(v))    /* Wait for frame header */
  360.     {
  361.     default:
  362.       return ERROR;
  363.     case ZFIN:
  364.       zshhdr(v, ZCOMPL);
  365.       sendbuf(v);
  366.       return ZFIN;
  367.     case ZNAK:
  368.     case TIMEOUT:
  369.       if (--n < 0)
  370.     return ERROR;
  371.       v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  372.       mysprintf(find_end(v->Msgbuf), GetLocaleString(MSG_AT_X_RETRIES_LEFT_TXT),
  373.         v->Rxbytes, (long) n);
  374.       v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  375.       ++v->xpru.xpru_timeouts;
  376.       (*v->io.xpr_update) (&v->xpru);
  377.       continue;
  378.     case ZFILE:        /* Sender didn't see our ZRPOS yet; try again */
  379.  
  380.       zrdata(v, v->Pktbuf, v->ksize);    /* Read and discard redundant */
  381.       continue;            /* filename packet */
  382.     case ZEOF:            /* End of file data */
  383.       if (v->Rxpos != v->Rxbytes)    /* We aren't in sync; go back */
  384.       {
  385.     mysprintf(v->Msgbuf, GetLocaleString(MSG_BAD_EOF_TXT),
  386.           v->Rxbytes, v->Rxpos);
  387.     upderr(v, v->Msgbuf);
  388.     continue;
  389.       }
  390.       bfclose(v);        /* All done; close file */
  391.       updmsg(v, GetLocaleString(MSG_EOF_RECEIVED_TXT));
  392.       return c;
  393.     case ERROR:        /* Too much garbage while waiting for frame header */
  394.       if (--n < 0)
  395.     return ERROR;
  396.       v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  397.       mysprintf(find_end(v->Msgbuf), GetLocaleString(MSG_AT_X_RETRIES_LEFT_TXT),
  398.         v->Rxbytes, (long) n);
  399.       v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  400.       ++v->xpru.xpru_errors;
  401.       (*v->io.xpr_update) (&v->xpru);
  402.       zmputs(v, v->Attn);
  403.       continue;
  404.     case ZSKIP:
  405.       v->Modtime = 1;
  406.       bfclose(v);
  407.       upderr(v, GetLocaleString(MSG_SKIP_COMMAND_RECEIVED_TXT));
  408.       return(c);
  409.     case ZDATA:        /* More file data packets forthcoming */
  410.       if (v->Rxpos != v->Rxbytes)    /* We aren't in sync; go back */
  411.       {
  412.     if (--n < 0)
  413.       return ERROR;
  414.     v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  415.     mysprintf(v->Msgbuf, GetLocaleString(MSG_DATA_AT_BAD_POSITION_TXT),
  416.           v->Rxbytes, v->Rxpos);
  417.     v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  418.     ++v->xpru.xpru_errors;
  419.     (*v->io.xpr_update) (&v->xpru);
  420.     zmputs(v, v->Attn);
  421.     continue;
  422.       }
  423.       /* Receive file data packet(s) */
  424.     moredata:
  425.       /* Give comm program its timeslice if it needs one */
  426.       if (v->io.xpr_chkmisc)
  427.     (*v->io.xpr_chkmisc) ();
  428.       /* Check for abort from comm program */
  429.       if (v->io.xpr_chkabort)
  430.       {
  431.         result = (*v->io.xpr_chkabort)();
  432.  
  433.         if (result < 0)
  434.         {
  435.       zshhdr(v, ZABORT);
  436.       sendbuf(v);
  437.       goto aborted;
  438.     }
  439.     else
  440.     {
  441.       if (result > 0)
  442.       {
  443.         abort = result;
  444.         zshhdr(v, ZSKIP);
  445.         sendbuf(v);
  446.       }
  447.     }
  448.       }
  449.       switch (c = zrdata(v, v->Pktbuf, v->ksize))
  450.       {
  451.       case ZCAN:
  452.       case RCDO:
  453.       aborted:
  454.     upderr(v, GetLocaleString(MSG_TRANSFER_CANCELED_TXT));
  455.     return ERROR;
  456.       case ERROR:        /* CRC error or packet too long */
  457.     if (--n < 0)
  458.       return ERROR;
  459.     v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  460.     mysprintf(find_end(v->Msgbuf), GetLocaleString(MSG_AT_X_RETRIES_LEFT_TXT),
  461.           v->Rxbytes, (long) n);
  462.     v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  463.     ++v->xpru.xpru_errors;
  464.     (*v->io.xpr_update) (&v->xpru);
  465.     zmputs(v, v->Attn);
  466.     continue;
  467.       case TIMEOUT:
  468.     if (--n < 0)
  469.       return ERROR;
  470.     v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  471.     mysprintf(find_end(v->Msgbuf), GetLocaleString(MSG_AT_X_RETRIES_LEFT_TXT),
  472.           v->Rxbytes, (long) n);
  473.     v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  474.     ++v->xpru.xpru_timeouts;
  475.     (*v->io.xpr_update) (&v->xpru);
  476.     continue;
  477.       case GOTCRCW:        /* Sender says it's waiting for an ACK */
  478.     n = v->ErrorLimit;
  479.     if (putsec(v) == ERROR)
  480.       return ERROR;
  481.     stohdr(v, v->Rxbytes);
  482.     zshhdr(v, ZACK);
  483.     sendbuf(v);
  484.     goto nxthdr;
  485.       case GOTCRCQ:        /* Sender says it's not waiting, */
  486.     /* but ACK anyway (rarely used) */
  487.     n = v->ErrorLimit;
  488.     if (putsec(v) == ERROR)
  489.       return ERROR;
  490.     stohdr(v, v->Rxbytes);
  491.     zshhdr(v, ZACK);
  492.     sendbuf(v);
  493.     goto moredata;
  494.       case GOTCRCG:        /* Sender says keep receiving, there's more coming */
  495.     n = v->ErrorLimit;
  496.     if (putsec(v) == ERROR)
  497.       return ERROR;
  498.     goto moredata;
  499.       case GOTCRCE:        /* Sender says this is the last packet */
  500.     n = v->ErrorLimit;
  501.     if (putsec(v) == ERROR)
  502.       return ERROR;
  503.     goto nxthdr;
  504.       }
  505.     }
  506.   }
  507. }                /* End of short rzfile() */
  508.  
  509. /**********************************************************
  510.  *      short procheader(struct Vars *v)
  511.  *
  512.  * Process file name & info packet; either open file and
  513.  * prepare to receive, or return ERROR if we should skip
  514.  * this one for some reason
  515.  **********************************************************/
  516. short procheader(struct Vars *v)
  517. {
  518.   struct SetupVars *sv;
  519.   UBYTE *p, *openmode, buff[PATHLEN];
  520.   long n;
  521.  
  522.   openmode = "w";
  523.   v->Strtpos = 0;
  524.  
  525.   /* Extract expected filesize from file info packet, if given */
  526.   v->Fsize = -1;
  527.   p = find_end(v->Pktbuf) + 1;
  528.  
  529.   if (*p)
  530.   {
  531.     STRPTR index, ptr;
  532.  
  533.     index = skip_chars(ptr = p);
  534.  
  535.     v->Fsize = Atol(ptr);
  536.  
  537.     index = skip_chars(ptr = index);
  538.  
  539.     v->Modtime = from_octal(ptr);
  540.  
  541.     skip_chars(ptr = index);
  542.  
  543.     v->Bits = from_octal(ptr);
  544.  
  545.     v->SetAttributes = TRUE;
  546.   }
  547.   else
  548.   {
  549.     v->Modtime = 0;
  550.     v->Bits = 0;
  551.     v->SetAttributes = FALSE;
  552.   }
  553.  
  554.   /* If option RY set, use full received file path */
  555.   sv = (void *) v->io.xpr_data;
  556.   if (*sv->option_r == 'Y')
  557.     strcpy(v->Filename, v->Pktbuf);
  558.   else
  559.   {
  560.     /* else use the default directory path specified in the setup options */
  561.     strcpy(v->Filename, sv->option_p);
  562.     p = v->Filename + strlen(v->Filename) - 1;
  563.     if (p >= v->Filename && *p != '/' && *p != ':')
  564.       *++p = '/';
  565.     *++p = '\0';
  566.     /* Append the filename from the file info packet; ignore anything before
  567.      * last /, \, or : in filename (received directory path is ignored)
  568.      */
  569.     p = find_end(v->Pktbuf);    /* start at end and scan back */
  570.     /* to start of name */
  571.     while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
  572.       --p;
  573.     strcat(v->Filename, ++p);
  574.   }
  575.  
  576.   /* Make sure we have room for file; skip it if not. */
  577.  
  578.   if (v->Fsize > getfree(v))
  579.   {
  580.     mysprintf(v->Msgbuf, GetLocaleString(MSG_INSUFFICIENT_DISK_SPACE_TXT),
  581.           v->Fsize, getfree(v));
  582.     upderr(v, v->Msgbuf);
  583.     v->Noroom = TRUE;
  584.     return ERROR;
  585.   }
  586.  
  587.   /* Display name of file being received for user */
  588.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  589.   v->xpru.xpru_filename = (char *) v->Filename;
  590.   (*v->io.xpr_update) (&v->xpru);
  591.  
  592.   /* If a file with this name already exists, handle in
  593.    * accordance with O option
  594.    */
  595.   if (exist(v))
  596.   {
  597.     switch (*sv->option_o)
  598.     {
  599.     case 'N':            /* Don't overwrite; change name to prevent collision */
  600.       strcpy(buff, v->Filename);
  601.       strcat(v->Filename, ".dup");
  602.       n = 2;
  603.       while (exist(v))
  604.       {
  605.     mysprintf(v->Filename, "%s.dup%ld", buff, n);
  606.     ++n;
  607.       }
  608.       /* Update filename display to show new name */
  609.       (*v->io.xpr_update) (&v->xpru);
  610.       break;
  611.     case 'R':            /* Resume transfer from current end of file */
  612.       openmode = "a";
  613.       v->Strtpos = (*v->io.xpr_finfo) (v->Filename, 1L);
  614.       break;
  615.     case 'S':            /* Skip it */
  616.       upderr(v, GetLocaleString(MSG_FILE_ALREADY_EXISTS_TXT));
  617.       return ERROR;
  618.       /* Else 'Y', go ahead and overwrite it (openmode = w) */
  619.     }
  620.   }
  621.  
  622.   /* Set text/binary mode according to options before opening file */
  623.   set_textmode(v);
  624.  
  625.   /* Figure out file translation mode to use; either binary (verbatim
  626.    * transfer) or ASCII (perform end-of-line conversions).  If user has
  627.    * specified a mode (TY or TN), that's what we use.  If user says use
  628.    * sender's suggestion (T?), set mode according to Zconv flag.  If neither
  629.    * side specifies, default to binary mode.
  630.    */
  631.   v->Thisbinary = v->Rxbinary || !v->Rxascii;
  632.   if (!v->Rxbinary && v->Zconv == ZCNL)
  633.     v->Thisbinary = FALSE;
  634.   if (!v->Rxascii && v->Zconv == ZCBIN)
  635.     v->Thisbinary = TRUE;
  636.  
  637.   /* Open the file (finally) */
  638.   if (!(v->File = bfopen(v, openmode)))
  639.   {
  640.     ++v->Errcnt;
  641.     upderr(v, GetLocaleString(MSG_CANT_OPEN_FILE_TXT));
  642.     return ERROR;
  643.   }
  644.   GetSysTime(&v->Starttime);
  645.   v->BytesReceived = 0;
  646.  
  647.   /* Initialize comm program transfer status display */
  648.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  649.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  650.     | XPRU_BYTES | XPRU_ELAPSEDTIME;
  651.   v->xpru.xpru_protocol = "ZModem";
  652.   v->xpru.xpru_filesize = v->Fsize;
  653.   v->xpru.xpru_msg = (v->Thisbinary) ? GetLocaleString(MSG_RECEIVING_BINARY_FILE_TXT)
  654.     : GetLocaleString(MSG_RECEIVING_TEXT_FILE_TXT);
  655.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  656.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  657.   v->xpru.xpru_bytes = v->Strtpos;
  658.   v->xpru.xpru_blocksize = v->ksize;
  659.   update_rate(v);
  660.   (*v->io.xpr_update) (&v->xpru);
  661.  
  662.   return OK;
  663. }                /* End of short procheader() */
  664.  
  665. /**********************************************************
  666.  *      short putsec(struct Vars *v)
  667.  *
  668.  * Writes the received file data to the output file.
  669.  * If in ASCII mode, stops writing at first ^Z, and converts all
  670.  * \r\n pairs or solo \r's to \n's.
  671.  **********************************************************/
  672. short putsec(struct Vars *v)
  673. {
  674.   static char nl = '\n';
  675.   UBYTE *p;
  676.   short n;
  677.  
  678.   /* If in binary mode, write it out verbatim */
  679.   if (v->Thisbinary)
  680.   {
  681.     if (bfwrite(v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
  682.       goto diskfull;
  683.     /* If in text mode, perform end-of-line cleanup */
  684.   }
  685.   else
  686.   {
  687.     if (v->Eofseen)
  688.       return OK;
  689.     for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
  690.     {
  691.       if (*p == CPMEOF)
  692.       {
  693.     v->Eofseen = TRUE;
  694.     return OK;
  695.       }
  696.       else if (*p != '\n' && v->Lastsent == '\r')
  697.       {
  698.     if (bfwrite(v, &nl, 1L) != 1)
  699.       goto diskfull;
  700.       }
  701.       if (*p != '\r' && bfwrite(v, p, 1L) != 1)
  702.     goto diskfull;
  703.       v->Lastsent = *p;
  704.     }
  705.   }
  706.  
  707.   /* Update comm program status display */
  708.   v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  709.     | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
  710.   ++v->xpru.xpru_blocks;
  711.   v->xpru.xpru_blocksize = v->Rxcount;
  712.   v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
  713.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  714.   update_rate(v);
  715.   (*v->io.xpr_update) (&v->xpru);
  716.  
  717.   return OK;
  718.  
  719. diskfull:
  720.   upderr(v, GetLocaleString(MSG_ERROR_WRITING_FILE_TXT));
  721.   v->Noroom = TRUE;
  722.   return ERROR;
  723. }                /* End of short putsec() */
  724.  
  725. /**********************************************************
  726.  *      void ackbibi(struct Vars *v)
  727.  *
  728.  * End of batch transmission; disengage cleanly from sender
  729.  **********************************************************/
  730. void ackbibi(struct Vars *v)
  731. {
  732.   short n;
  733.  
  734.   stohdr(v, 0L);
  735.   for (n = 4; --n;)
  736.   {
  737.     zshhdr(v, ZFIN);
  738.     sendbuf(v);
  739.     switch (readock(v, 100))
  740.     {
  741.     case 'O':
  742.       readock(v, 1);        /* Discard 2nd 'O' */
  743.     case TIMEOUT:
  744.     case RCDO:
  745.       return;
  746.     }
  747.   }
  748. }                /* End of void ackbibi() */
  749. /* End of Receive.c source */
  750.